#include <iostream>
#include <cstdint>
#include <cassert>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <math.h>
#include <unordered_set>
#include <set>
using namespace std;
#ifdef DEBUG // DEBUG在本地g++编译时定义，上传至官网后不会被定义
    #define LOG_INIT(LOG_FILE_PATH) {freopen(LOG_FILE_PATH, "w+", stderr);}
    #define LOG_INFO(arg...) {fprintf(stderr, ##arg); fflush(stderr);}
    #define LOG_LINE() LOG_INFO("####################################################################################\n");
    #define LOG(arg...) {fprintf(stderr, "%s:%d > ", __FILE__, __LINE__); fprintf(stderr, ##arg);}
    #define ASSERT(state) assert(state)
#else
    #define LOG_INIT(...)
    #define LOG_INFO(...)
    #define LOG_LINE(...)
    #define LOG(...)
    #define ASSERT(...)
#endif // DEBUG

#define ASSERT_ID(id, vec) ASSERT(id > 0 && (id - 1) < vec.size())


class disk;
class slice;
class controller;
class tag;
class object;

// 最大时间片
int MAX_CEIL = 1800;
// 读写删除操作计数变量
int OP_NUM = 3;
// 对象存储
vector<object> objects;
// 标签存储
vector<tag> tags;
// 磁盘存储
vector<disk> disks;
// <id, objects_id> map
unordered_map<int, int> objects_map;
// 时间片 标签数 硬盘数 存储单元数 token数量
int t, m, n, v, g;
// 已经读取了的block 需要有访问功能 已经访问的block列表
set<pair<int, int>> has_read_block;
// 1800个时间片为一个周期
size_t FRE_PER_SLICING(1800);
// 额外的时间
size_t EXTRA_TIME(105);
// 对象类 
// 仅做存储
class object {
    // 操作标签
    // id
    size_t id;
    // 大小
    size_t size;
    // 对象标签
    size_t tag;
    // 每个副本的存储位置
    vector<slice> slices = vector<slice>(3);

    public:
        object() {}

        object(size_t id, size_t size, size_t tag) : id(id), size(size), tag(tag) {}

        size_t get_id() {
            return id;
        }
        
        size_t get_size() {
            return size;
        }
        
        size_t get_tag() {
            return tag;
        }
        
        vector<slice>& get_slices() {
            return slices;
        }

        const vector<slice>& get_slices() const{
            return slices;
        }

        bool is_block_read(size_t b_id) {
            ASSERT(b_id >= 0 && b_id < size);
            return has_read_block.find(make_pair(id, b_id)) != has_read_block.end();
        }

        void set_read_block(size_t b_id) {
            has_read_block.insert(make_pair(id, b_id));
        }

        // void set_slices(vector<slice> slices) {
        //     ASSERT(slices.size() == 3);
        //     for (int i = 0; i < 3; ++i) {
        //         this->slices[i] = slices[i];
        //     }
        // }
};

object& get_object_by_id(size_t id) {
    return objects[objects_map[id]];
}

class mem_unit {
    // 对象ID
    size_t o_id;
    // 副本ID
    size_t s_id;
    // 对象块ID
    size_t b_id;
    // 是否已读 false true
    bool read;

    public:
        mem_unit() : o_id(0), s_id(0), b_id(0), read(false) {}
        
        mem_unit(size_t o_id, size_t s_id, size_t b_id) : o_id(o_id), s_id(s_id), b_id(b_id), read(false) {}
        
        // 判断该存储单元是否为空
        bool is_null() {
            if (o_id == 0 && b_id == 0 && s_id == 0) {
                return true;
            }
            return false;
        }

        void set_o_id(size_t o_id) {
            this->o_id = o_id;
        }

        void set_s_id(size_t s_id) {
            this->s_id = s_id;
        }

        void set_b_id(size_t b_id) {
            this->b_id = b_id;
        }

        size_t get_o_id() {
            return o_id;
        }
        
        size_t get_s_id() {
            return s_id;
        }

        size_t get_b_id() {
            return b_id;
        }

        void read_unit() {
            set_read(true);
        }

        bool is_read() {
            return read;
        }

        void set_read(bool is_read) {
            this->read = is_read;
        }
        // 存储的时候肯定是read为false
        void store(size_t o_id, size_t s_id, size_t b_id, bool read = false) {
            set_o_id(o_id);
            set_s_id(s_id);
            set_b_id(b_id);
            set_read(read);
        }
};


// 磁盘类
//仅做存储
class disk {
    // 容量
    size_t capcity;
    // 磁盘指针
    size_t cursor;
    // 存储单元
    vector<mem_unit> mem;
    // 剩余token量
    size_t tokens;
    // 剩余单元量
    size_t null_cnt;
    // 上一次操作消耗的tokens
    size_t last_tokens;
    // 上一次操作 0 默认 1 Jump 2 Pass 3 Read
    size_t last_op;

    public:
        disk() {}

        disk(size_t capcity, size_t tokens) : capcity(capcity), mem(capcity), null_cnt(capcity), last_tokens(0), last_op(0), tokens(tokens) {};

        size_t get_null_cnt() {
            return null_cnt;
        }

        size_t get_capcity() {
            return capcity;
        }

        void set_mem(size_t o_id, size_t s_id, size_t b_id, size_t pos) {
            // 传入时确保这个是空的
            ASSERT(pos >= 0 && pos < capcity);
            mem[pos].store(o_id, s_id, b_id);
            null_cnt--;
        }
        
        size_t get_last_op() {
            return last_op;
        }

        size_t get_last_tokens() {
            return last_tokens;
        }

        void set_last_op(size_t last_op) {
            this->last_op = last_op;
        }

        void set_last_tokens(size_t last_tokens) {
            assert(last_tokens <= g);
            this->last_tokens = last_tokens;
        }

        size_t get_tokens() {
            return tokens;
        }

        void set_tokens(size_t tokens) {
            this->tokens = tokens;
        }
        void set_cursor(size_t cursor) {
            assert(cursor >= 0 && cursor < v);
            this->cursor = cursor;
        }
        
        size_t get_cursor() {
            return cursor;
        }
        
        // 计算tar与磁头的距离
        size_t cal_dis(size_t tar) {
            ASSERT(tar >=0 && tar < capcity);
            return (tar - cursor + v) % v;
        }
        // 计算到目标位置所需要的现在的cursor所需要的tokens 
        size_t cal_token(int target) {
            // 距离
            int dis = (target - cursor + v) % v;
            int j_token = g + 64;
            int p_token = dis + 64;
            int r_token = INT16_MAX;
            if (last_op == 3) {
                size_t last_t = last_tokens;
                r_token = 0;
                while (dis--) {
                    last_t = std::max(16, (int) ceil(last_t));
                    r_token += last_t;
                }
            }
            return min(j_token, min(p_token, r_token));
        }

        // 移动到target并读取的方案
        // 1 为JUMP然后读取
        // 2 为PASS然后读取
        // 3 为READ然后读取
        size_t read_to_plan(int target) {
            // 距离
            int dis = (target - cursor + v) % v;
            int j_token = g + 64;
            int p_token = dis + 64;
            int r_token = INT16_MAX;
            if (last_op == 3) {
                size_t last_t = last_tokens;
                r_token = 0;
                while (dis--) {
                    last_t = std::max(16, (int) ceil(last_t));
                    r_token += last_t;
                }
            }
            if (j_token < p_token && j_token < r_token) {
                return 1;
            }
            if (p_token < r_token && p_token < j_token) {
                return 2;
            }
            if (r_token < j_token && r_token < p_token) {
                return 3;
            }
            return 0;
        }

        size_t find_next_block(object& obj) {
            size_t pos = cursor;
            while (mem[pos].get_o_id() != obj.get_id()) {
                pos = (pos + 1) % capcity;
            }
            return pos;
        }

        // 移动到目标位置并且读取
        // 模拟用
        bool to_pos_and_read(size_t target) {
            size_t plan = read_to_plan(target);
            int dis = (target - cursor + v) % v;
            if (plan == 1) {
                // 直接JUMP
                LOG_INFO("CURRENT TOKEN%ld", tokens);
                if (tokens >= g) {
                    jump(target);
                }
                // 在模拟时会进入这个判断
                if (tokens >= 64) {
                    read();
                }
            }
            if (plan == 2) {
                while(dis-- && tokens > 0) {
                    pass();
                }
                if (tokens >= 64) {
                    read();
                }
            }
            if (plan == 3) {
                while (dis-- && tokens > 0) {
                    read();
                }
            }
            if (cursor == target && mem[cursor].is_read()) {
                return true;
            }
            return false;
        }

        // 附带操作队列
        bool to_pos_and_read(size_t target, string& ops) {
            size_t plan = read_to_plan(target);
            int dis = (target - cursor + v) % v;
            LOG_INFO("PLAN%d\n", plan);
            if (plan == 1) {
                // 直接JUMP
                if (tokens >= g) {
                    jump(target);
                    ops += "j " + std::to_string(target + 1);
                } else {
                    // tokens 直接跳转
                    return false;
                }
                // 在模拟时会进入这个判断
                if (tokens >= 64) {
                    LOG_INFO("JUMP AND READ\n");
                    ops += 'r';
                    read();
                }
            }
            if (plan == 2) {
                while(dis-- && tokens > 0) {
                    ops += 'p';
                    pass();
                }
                if (tokens >= 64) {
                    ops += 'r';
                    read();
                }
            }
            if (plan == 3) {
                while (dis-- && tokens > 0) {
                    ops += 'r';
                    read();
                }
            }
            if (cursor == target && mem[cursor].is_read()) {
                if (plan == 1) {
                    LOG_INFO("TESTEST%ld\n", cursor);
                }
                return true;
            }
            return false;
        }
        // 采用JUMP的操作
        void jump(size_t target) {
            // 一定要有足够多的token
            ASSERT(tokens >= g);
            cursor = target;
            tokens -= g;
            last_tokens = g;
            last_op = 1;
        }
        
        // 采用PASS的操作
        void pass() {
            ASSERT(tokens > 0);
            cursor = (cursor + 1 + capcity) % capcity;
            tokens--;
            last_op = 2;
            last_tokens = 2;
        }

        // 采用read操作
        // false: 剩余的token量不够操作
        bool read() {
            ASSERT(tokens > 0);
            if (last_op == 3) {
                size_t now = std::max(16, (int) ceil(last_tokens));
                if (now < tokens) {
                    return false;
                }
                mem[cursor].read_unit();
                cursor = (cursor + 1 + capcity) % capcity;
                tokens -= now;
                last_tokens = now;
                last_op = 3;
            } else {
                if (tokens < 64) {
                    return false;
                }
                mem[cursor].read_unit();
                cursor = (cursor + 1 + capcity) % capcity;
                tokens -= 64;
                last_tokens = 64;
                last_op = 3;
            }
            return true;
        }

        // 释放某个存储单元
        void free_mem(size_t pos) {
            ASSERT(pos >= 0 && pos < capcity);
            mem[pos].store(0, 0, 0);
            null_cnt++;
        }

        // 获取第i个存储单元
        mem_unit& operator[](size_t index) {
            ASSERT(index >= 0 && index < mem.size());
            return mem[index];
        }
};

// 仅做存储
class slice {
    // 磁盘编号 -1为没有存储
    int disk_id;
    // 存储位置编号 -1为没有存储
    // 不能用编号来存 得用vector来存
    vector<int> pos;

    public:
        slice() : disk_id(-1), pos(0) {}

        slice(int disk_id) : disk_id(disk_id), pos(0) {}

        int get_disk_id() {
            return disk_id;
        }

        vector<int> get_pos() {
            return pos;
        }

        void set_disk_id(size_t disk_id) {
            this->disk_id = disk_id;
        }
        
        void add_pos(size_t position) {
            pos.push_back(position);
        }
};



// 标签类
class tag {
    size_t read;

    size_t del;

    size_t write;

    public:

        tag() {}
        
        tag(size_t read, size_t del, size_t write) : read(read), del(del), write(write) {}

        void set_read(size_t read) {
            this->read = read;
        }
        
        void set_del(size_t del) {
            this->del = del;            
        }

        void set_write(size_t write) {
            this->write = write;
        }
};

// 读请求类
class request {
    // 请求ID
    size_t id;
    // 对象ID
    size_t o_id;
    // 分数
    size_t score;
    
    public:
        request() {}

        request(size_t id, size_t o_id, size_t score = SIZE_MAX) : id(id), o_id(o_id) {}

        void set_id(size_t id) {
            this->id = id;
        }
        
        void set_o_id(size_t o_id) {
            this->o_id = o_id;
        }

        size_t get_id() const{
            return id;
        }

        size_t get_o_id() const{
            return o_id;
        }

        bool operator==(const request& request) const{
            return this->id == request.get_id() && this->o_id == request.get_o_id();
        }
        // 更新分数
        // @param cursors 当前指针状态 object 所在信息 
        // size_t update_score(const vector<cursor>& cursors, const object& object) {
        //     //  简单算法 直接只选一个副本来实现
        //     // TODC 更新算法
        // }
};

class request_hash {
    public:
    std::size_t operator()(const request& req) const {
        std::size_t h1 = std::hash<int>{}(req.get_id());
        std::size_t h2 = std::hash<int>{}(req.get_o_id());
        return h1 ^ (h2 << 1);
    }
};
// class cursor {
//     // 位置
//     size_t pos;
//     // 上一次操作 默认0 Jump1 Pass2 Read3
//     size_t last_op;
//     // tokens余量
//     size_t tokens;
//     // 上一次操作消耗的token
//     size_t last_tokens;

//     public:
//         cursor () : pos(0), last_op(0) {}

//         cursor (size_t tokens, size_t pos = 0, size_t last_op = 0) : tokens(tokens) {}

//         void set_last_op(size_t last_op) {
//             this->last_op = last_op;
//         }

//         void set_pos(size_t pos) {
//             this->pos = pos;
//         }

//         void set_tokens(size_t tokens) {
//             this->tokens = tokens;
//         }

//         size_t get_last_op() {
//             return last_op;
//         }

//         size_t get_tokens() {
//             return tokens;
//         }
        
//         size_t get_pos() {
//             return pos;
//         }

//         // 计算到目标位置要的最小token 记录cursor这次的操作 用于排序
//         // tar目标位置
//         size_t cal_token(int target) {
//             // 距离
//             int dis = (target - pos + v) % v;
//             int j_token = g +64;
//             int p_token = dis + 64;
//             int r_token = INT16_MAX;
//             if (last_op == 3) {
//                 size_t last_t = last_tokens;
//                 r_token = 0;
//                 while (dis--) {
//                     last_t = std::max(16, (int) ceil(last_t));
//                     r_token += last_t;
//                 }
//             }
//             return min(j_token, min(p_token, r_token));
//         }
// };

class read_block {
    size_t req_id;

    size_t o_id;

    size_t b_id;

    size_t score;

    const object& ojt;

    public:

        read_block(size_t req_id, size_t o_id, size_t b_id, size_t score = SIZE_MAX) : req_id(req_id), o_id(o_id), b_id(b_id), ojt(get_object_by_id(o_id)) {}

        // 更新读该对象该block的score

        // size_t update_score (const vector<cursor>& cursors) {
        //     for (int i = 0; i < 3; ++i) {
        //         auto s = ojt.get_slices()[i];
        //         int d_id = s.get_disk_id();
        //         auto c = cursors[d_id];
        //         // 这次消耗的内存
        //         this->score = c.cal_token(s.get_pos()[b_id]);
        //     }
        // }
};

class todo_unit {
    size_t pos;
    todo_unit* next;
    public:
        todo_unit() {
            next = nullptr;
            pos = -1;
        }

        todo_unit(size_t pos) : pos(pos) {}

        
};

// 设计一个处理器来处理时间片信息 该队列是单例的
class controller {
    // 当前所在时间戳
    size_t time_stamp;
    // 待处理的读请求
    unordered_set<request, request_hash> undo_read_req;
    // 待上报的请求
    vector<size_t> success_req;
    // 待处理的block
    vector<read_block> undo_read_block;
    // 磁盘待读取队列 是一个环状链表 头是当前磁头的位置 没读一个
    vector<vector<size_t> > read_queues;
    // 当前的处理状态: 删除(1)、写(2)、读(3)、未开始(0)
    size_t status = 0;
    public:
        // 当前时间戳 n为磁盘大小
        controller(size_t time_stamp) : time_stamp(time_stamp), read_queues(n) {}

        // 处理读写删除请求
        void handle_req() {
            if (status == 1) {
                handle_delete();
            }
            if (status == 2) {
                handle_write();
            }
            if (status == 3) {
                handle_read();
            }
        }

        // 处理删除
        void handle_delete() {
            status++;
            int n;
            vector<request> report_list;
            scanf("%d", &n);
            for (int i = 0; i < n; ++i) {
                int now;
                scanf("%d", &now);
                object& o = get_object_by_id(now);
                auto slices = o.get_slices();
                // 在已读block中删除
                for (int i = 0; i < o.get_size(); ++i) {
                    if (o.is_block_read(i)) {
                        // 删除已读block
                        has_read_block.erase(make_pair(o.get_id(), i));
                    }
                }
                // 删除所有的信息  可能需要做？
                // 删除所有副本
                for (int k = 0; k < 3; ++k) {
                    size_t disk_id = slices[k].get_disk_id();
                    vector<int> pos = slices[k].get_pos();
                    for (auto p : pos) {
                        // 释放内存
                        disks[disk_id].free_mem(p);
                    }
                    // 删除该副本
                    slices[i].set_disk_id(-1);
                }
                
                for (auto req : undo_read_req) {
                    if (req.get_o_id() == now) {
                        // 删除该请求
                        report_list.push_back(req);
                        
                    }
                }
            }
            // 上报
            std::cout << report_list.size() << endl;
            for (auto req : report_list) {
                undo_read_req.erase(req);
                std::cout << req.get_id() << std:: endl;
            }
            // 清空输出缓存区域
            std::cout.flush();
        }

        // s_id为副本号 0 1 2
        void store_slice(object& o, size_t s_id) {
            int stored_disks[2];
            int k = 0;
            for (int i = 0; i < 3; ++i) {
                if (i == s_id) {
                    continue;
                } 
                stored_disks[k++] = o.get_slices()[i].get_disk_id();
            }
            for (int i = 0; i < disks.size(); ++i) {
                // 其他副本存在这个盘里面
                if (i == stored_disks[0] || i == stored_disks[1]) {
                    continue;
                }
                // 闲置空间不够
                if (disks[i].get_null_cnt() < o.get_size()) {
                    continue;
                }
                // 找空位
                // 当前存的对象块序号
                size_t b_ptr = 0;
                for (int j = 0; j < disks[i].get_capcity(); ++j) {
                    if (b_ptr >= o.get_size()) {
                        break;
                    }
                    if (disks[i][j].is_null()) {
                        disks[i].set_mem(o.get_id(), s_id, b_ptr, j);
                        o.get_slices()[s_id].add_pos(j);
                        b_ptr++;
                    }
                }
                o.get_slices()[s_id].set_disk_id(i);
                // TODO 存储该副本在磁盘上的存储单元编号
                break;
            }
        }

        // 读取时间戳
        void read_timestamp() {
            int timestamp;
            scanf("%*s%d", &timestamp);
            this->time_stamp = timestamp;
            printf("TIMESTAMP %d\n", timestamp);
            LOG_INFO("TIMESTAMP %d\n", timestamp);
        }

        // 处理写入
        void handle_write() {
            status++;
            int n;
            vector<size_t> report_list;
            scanf("%d", &n);
            for (int i = 0; i < n; ++i) {
                // 扫描数据
                // scanf();
                int id, size, tag;
                scanf("%d%d%d", &id, &size, &tag);
                // 读取对象数据
                object o = object(id, size, tag);
                // 存储至存储单元
                for (int j = 0; j < 3; ++j) {
                    store_slice(o, j);
                }
                // 存储到对象
                objects.push_back(o);
                objects_map[id] = objects.size() - 1;
                // 上报写入结果
                report_list.push_back(id);
            }
            //上报
            for (auto id : report_list) {
                std::cout << id << endl;
                object& o = get_object_by_id(id);
                for (int i = 0; i < 3; ++i) {
                    std::cout << o.get_slices()[i].get_disk_id() + 1 << " ";
                    auto pos = o.get_slices()[i].get_pos();
                    for (auto p : pos) {
                        std::cout << p + 1 << " ";
                    }
                    std::cout << endl;
                }
            }
            std::cout.flush();
        }

        // 处理读取
        void handle_read() {
            status++;
            int n;
            scanf("%d", &n);
            for (int i = 0; i < n; ++i) {
                // 扫描数据
                int req_id, id;
                scanf("%d%d", &req_id, &id);
                // 加入未处理请求中
                undo_read_req.insert(request(req_id, id));
                auto o = get_object_by_id(id);
                // 如果有相同对象ID的读请求 就忽略 TODO 好像不用做这个 相同对象ID的读请求要重复汇报
                // 预处理读请求
                preprocess_read_req(o);
            }
            LOG_INFO("finish preprocess read %ld\n", time_stamp);
            // 处理读队列
            do_read();
            // 报告完成的读请求
            do_report_req();
        }
        
        // 报告完成的读请求
        void do_report_req() {
            vector<request> report_list;
            for (auto req : undo_read_req) {
                bool flag = true;
                object& o = get_object_by_id(req.get_o_id());
                for (int i = 0; i < o.get_size(); ++i) {
                    if (!o.is_block_read(i)) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    // 
                    report_list.push_back(req);
                    // 删除该请求
                    undo_read_req.erase(req);
                    // 汇报该请求
                }
            }
            //cout
            std::cout << report_list.size() << endl;
            for (int i = 0; i < report_list.size(); ++i) {
                std::cout << report_list[i].get_id() << endl;
            }
            std::cout.flush();
        }

        // 预处理读请求 
        // 确定读哪个块的副本 将block加入到队列中
        // 当前策略：每三分之一决定用哪一个磁盘来读取
        void preprocess_read_req(object& obj) {
            size_t p[3];
            size_t s = obj.get_size();
            // 每个磁盘承载三分之一的读取量 这样并行的效率是最高的
            // 两两比对
            // 待读取的队列
            vector<size_t> todo_blocks;
            for (int i = 0; i < s; ++i) {
                if (obj.is_block_read(i)) {
                    continue;
                }
                todo_blocks.push_back(i);
            }
            // 每个block选择最优的slice
            // todo_unit 待读取的存储单元 pair<磁盘号, 单元号>
            vector<pair<int, int>> todo_unit = pick_best_slice(obj, todo_blocks);
            // 加入到每个磁盘待读取的队列中 TODO
            for (auto unit : todo_unit) {
                size_t disk_id = unit.first;
                size_t unit_id  = unit.second;
                auto it = read_queues[disk_id].begin();
                for (; it != read_queues[disk_id].end(); ++it) {
                    if (disks[disk_id].cal_dis(*it) < disks[disk_id].cal_dis(unit_id)) {
                        continue;
                    }
                    read_queues[disk_id].insert(it, unit_id);
                    break;
                }
                if (it == read_queues[disk_id].end()) {
                    read_queues[disk_id].insert(it, unit_id);
                }
            }
        }

        vector<pair<int, int>> pick_best_slice(object& obj, vector<size_t> todo_blocks) {
            size_t s = obj.get_size();
            // 最大大小为三分之一 可以
            size_t max_b = ceil(s * 0.34);
            size_t d0 = obj.get_slices()[0].get_disk_id();
            size_t d1 = obj.get_slices()[1].get_disk_id();
            size_t d2 = obj.get_slices()[3].get_disk_id();
            vector<disk> tar_disks(3);
            // 复制三个磁盘 用于模拟
            tar_disks[0] = disk(disks[d0]);
            tar_disks[1] = disk(disks[d1]);
            tar_disks[2] = disk(disks[d2]);
            // 设置为满大小
            tar_disks[0].set_tokens(SIZE_MAX);
            tar_disks[1].set_tokens(SIZE_MAX);
            tar_disks[2].set_tokens(SIZE_MAX);
            // 三个磁盘待读取的单元
            set<size_t> todo_units[3];
            // 忽略 tokens 因为在这里就只是
            while (todo_units[0].size() < max_b && todo_units[1].size() < max_b) {
                size_t pos0 = tar_disks[0].find_next_block(obj);
                size_t pos1 = tar_disks[1].find_next_block(obj);
                if (tar_disks[0][pos0].get_b_id() == tar_disks[1][pos1].get_b_id()) {
                    // 相等的取tokens消耗小的那个
                    size_t t0 = tar_disks[0].cal_token(pos0);
                    size_t t1 = tar_disks[1].cal_token(pos1);
                    if (t0 < t1) {
                        todo_units[0].insert(tar_disks[0][pos0].get_b_id());
                        // 更改当前的cursor状态
                        tar_disks[0].to_pos_and_read(pos0);
                    } else {
                        todo_units[1].insert(tar_disks[1][pos1].get_b_id());
                        // 更改当前的cursor状态
                        tar_disks[1].to_pos_and_read(pos1);
                    }
                } else {
                    // 不相等就各自读取各自的
                    todo_units[0].insert(tar_disks[0][pos0].get_b_id());
                    todo_units[1].insert(tar_disks[1][pos1].get_b_id());
                    // 更新cursor状态
                    tar_disks[0].to_pos_and_read(pos0);
                    tar_disks[0].to_pos_and_read(pos1);
                }
            }
            // 
            vector<pair<int, int> > res;
            for (int i = 0; i < s; ++i) {
                // 是用哪个副本来存得到该对象的第i个block
                int j;
                if (todo_units[0].find(i) != todo_units[0].end()) {
                    j = 0;
                } else if (todo_units[1].find(i) != todo_units[1].end()) {
                    j = 1;
                } else {
                    j = 2;
                }
                res.push_back(make_pair(obj.get_slices()[j].get_disk_id(), obj.get_slices()[j].get_pos()[i]));
            };
            return res;
        }
        // 对磁盘待读取队列进行操作
        void do_read() {
            // TODO 重新指定读取策略
            // TODO 需要重新写
            for (int i = 0; i < read_queues.size(); ++i) {
                string op = "";
                for (auto it = read_queues[i].begin(); it != read_queues[i].end(); it++) {
                    size_t u_id = *it;
                    if (!disks[i].to_pos_and_read(u_id, op)) {
                        break;
                    }
                    has_read_block.insert(make_pair(i, u_id));
                    read_queues[i].erase(it);
                }
                // 上报磁头操作
                if (op.size() > 0 && op[0] == 'j') {
                    std::cout << op << endl;
                } else {
                    op += '#';
                    std::cout << op << endl;
                }
            }
            std::cout.flush();
            // TODO 补充磁头操作的上报
        }

        // 时间片结束后进行的处理
        // 重置token
        // 上报完成的请求
        void clear() {
            for (int i = 0; i < n; ++i) {
                disks[i].set_tokens(g);
            }
        }
};

int main(int argc, char **argv) {
    LOG_INIT(argc > 1 ? argv[1] : "log/log.txt"); // 程序运行时第一个参数传递log输出位置
    LOG_LINE();
    LOG_INFO("编译时间[%s %s]\n", __DATE__, __TIME__)
    LOG_LINE();
    //
    freopen("./data/sample_practice.in", "r", stdin);
    freopen("./log/print.txt", "w", stdout);
    scanf("%d%d%d%d%d", &t, &m, &n, &v, &g);
    tags = vector<tag>(m+1);
    disks = vector<disk>();
    for (int i = 0; i < n; ++i) {
        disks.push_back(disk(v, g));
    }
    // 读取对象标签
    for (int j = 0; j < OP_NUM; ++j) {
        for (int i = 1; i <= m; ++i) {
            int now;
            for (int k = 1; k <= (t - 1) / FRE_PER_SLICING + 1; k++) {
                scanf("%d", &now);
                if (j == 0) {
                    tags[i].set_del(now);
                }
                if (j == 1) {
                    tags[i].set_write(now);
                }
                if (j == 2) {
                    tags[i].set_read(now);
                }
            }
        }
    }
    printf("OK\n");
    // 读取每个时间戳的操作
    controller control = controller(0);
    for (int i = 1; i <= t + EXTRA_TIME; ++i) {
        control.read_timestamp();
        control.handle_delete();
        control.handle_write();
        control.handle_read();
        control.clear();
    }
    return 0;
}